﻿// Copyright 2010 Maxime Serrano <lastchronicler@gmail.com>
// Copyright 2009, 2010 Matvei Stefarov <me@matvei.org>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;
using System.Threading;

namespace ForgeCraft
{
    public static class WarpDB
    {
        public const string DBFile = "WarpDB.txt",
                            Header = "location,world,createdDate,minPermission," +
                                     "ownerName,isPublic,warpName";

        public static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

        public static void AddWarp(int x, byte y, int z, string warpName, string world = "", bool isPublic = true, byte minPermission = 0)
        {
            BlockPosition bp = new BlockPosition(x, y, z);

            if (Server.DBWarpList.ContainsKey(bp))
            {
                return;
            }

            string[] list = new string[WarpInfo.fieldCount];

            list[0] = x + ":" + y + ":" + z;
            list[1] = "";
            list[2] = DateTime.UtcNow.ToString();
            list[3] = minPermission.ToString();
            list[4] = "console";
            list[5] = isPublic.ToString();
            list[6] = warpName;

            WarpInfo info = new WarpInfo(list);

            Server.DBWarpList.Add(bp, info);
        }

        public static void AddWarp(Player p, string warpName, bool isPublic = true, byte minPermission = 0)
        {
            BlockPosition bp = new BlockPosition((int)p.pos.x, (byte)p.pos.y, (int)p.pos.z);

            if (Server.DBWarpList.ContainsKey(bp))
            {
                p.Message("Another warp is already registered at this location!");
                return;
            }

            string[] list = new string[WarpInfo.fieldCount];

            list[0] = (int)p.pos.x + ":" + (byte)p.pos.y + ":" + (int)p.pos.z;
            list[1] = p.currentWorld.name;
            list[2] = DateTime.UtcNow.ToString();
            list[3] = minPermission.ToString();
            list[4] = p.name;
            list[5] = isPublic.ToString();
            list[6] = warpName;

            WarpInfo info = new WarpInfo(list);

            Server.DBWarpList.Add(bp, info);
        }

        public static void RemoveWarp(Player p, int x, byte y, int z)
        {
            BlockPosition bp = new BlockPosition(x, y, z);

            WarpInfo info;

            if (Server.DBWarpList.TryGetValue(bp, out info))
            {
                if (info != null)
                {
                    if (info.ownerName == p.name)
                    {
                        Server.DBWarpList.Remove(bp);
                    }
                    else
                    {
                        p.Message("<!> This warp owned by another player!");
                        return;
                    }
                }
            }
        }

        public static void RemoveWarp(int x, byte y, int z)
        {
            BlockPosition bp = new BlockPosition(x, y, z);

            if (Server.DBWarpList.ContainsKey(bp))
            {
               Server.DBWarpList.Remove(bp);
            }
        }

        public static void Load()
        {
            if (File.Exists(DBFile))
            {
                locker.EnterWriteLock();
                try
                {
                    using (StreamReader reader = File.OpenText(DBFile))
                    {
                        reader.ReadLine(); // header
                        while (!reader.EndOfStream)
                        {
                            string[] fields = reader.ReadLine().Split(',');
                            if (fields.Length == WarpInfo.fieldCount)
                            {
                                try
                                {
                                    WarpInfo info = new WarpInfo(fields);

                                    BlockPosition bp = new BlockPosition(int.Parse(info.location.Split(':')[0]), byte.Parse(info.location.Split(':')[1]), int.Parse(info.location.Split(':')[2]));

                                    if (!Server.DBWarpList.ContainsKey(bp))
                                    {
                                        Server.DBWarpList.Add(bp, info);
                                    }
                                    else
                                    {
                                        Logger.Log("WarpDB.Load: Duplicate record for warp \"{0} ({1})\" skipped.", LogType.Error, info.location, info.warpName);
                                    }
                                }
                                catch (FormatException ex)
                                {
                                    Logger.Log("WarpDB.Load: Could not parse a record: {0}.", LogType.Error, ex.Message);
                                }
                                catch (IOException ex)
                                {
                                    Logger.Log("WarpDB.Load: Error while trying to read from file: {0}.", LogType.Error, ex.Message);
                                }
                            }
                        }
                    }
                }
                finally
                {
                    locker.ExitWriteLock();
                }
                Logger.Log("WarpDB.Load: Done loading player DB ({0} records).", LogType.DBActivity, Server.DBWarpList.Count);
            }
            else
            {
                Logger.Log("WarpDB.Load: No player DB file found.", LogType.Warning);
            }
        }

        public static void Save()
        {
            Logger.Log("WarpDB.Save: Saving player database ({0} records).", LogType.DBActivity, Server.DBWarpList.Count);
            string tempFile = Path.GetTempFileName();
            locker.EnterReadLock();
            try
            {
                using (StreamWriter writer = File.CreateText(tempFile))
                {
                    writer.WriteLine(Header);

                    foreach (KeyValuePair<BlockPosition, WarpInfo> kvp in Server.DBWarpList)
                    {
                        string[] list = new string[WarpInfo.fieldCount];

                        list[0] = kvp.Key.x + ":" + kvp.Key.y + ":" + kvp.Key.z;
                        list[1] = kvp.Value.world.ToString();
                        list[2] = kvp.Value.createdDate.ToString();
                        list[3] = kvp.Value.minPermission.ToString();
                        list[4] = kvp.Value.ownerName;
                        list[5] = kvp.Value.isPublic.ToString();
                        list[6] = kvp.Value.warpName;

                        WarpInfo entry = new WarpInfo(list);

                        writer.WriteLine(entry.Serialize());
                    }
                }
            }
            finally
            {
                locker.ExitReadLock();
            }
            try
            {
                File.Delete(DBFile);
                File.Move(tempFile, DBFile);
            }
            catch (Exception ex)
            {
                Logger.Log("WarpDB.Save: An error occured while trying to save PlayerDB: " + ex, LogType.Error);
            }
        }


    }
}
